package pg;

public class Triangulo {

  private Ponto vertice1, vertice2, vertice3;
  private Vetor normal;

  public Triangulo(Ponto vertice1, Ponto vertice2, Ponto vertice3) {
    this.vertice1 = vertice1;
    this.vertice2 = vertice2;
    this.vertice3 = vertice3;
    this.calcularNormal();
  }

  public Ponto getVertice1() {
    return vertice1;
  }

  public Ponto getVertice2() {
    return vertice2;
  }

  public Ponto getVertice3() {
    return vertice3;
  }

  public void setVertice1(Ponto vertice1) {
    this.vertice1 = vertice1;
    this.calcularNormal();
  }

  public void setVertice2(Ponto vertice2) {
    this.vertice2 = vertice2;
    this.calcularNormal();
  }

  public void setVertice3(Ponto vertice3) {
    this.vertice3 = vertice3;
    this.calcularNormal();
  }

  public void setNormal(Vetor normal) {
    this.normal = normal;
  }

  private void calcularNormal() {
    Vetor v1 = new Vetor(this.vertice1, this.vertice2);
    Vetor v2 = new Vetor(this.vertice1, this.vertice3);

    this.normal = Vetor.produtoVetorial(v1, v2);
    this.normal.normalizar();
  }

  public Vetor getNormal() {
    return this.normal;
  }


  private float determinante(Ponto a, Ponto b, Ponto c) {
      float soma = ( (a.getX() * b.getY() * c.getZ()) +
                    (b.getX() * c.getY() * a.getZ()) +
                    (c.getX() * a.getY() * b.getZ()));
      float diferenca = ( (c.getX() * b.getY() * a.getZ()) +
                         (a.getX() * c.getY() * b.getZ()) +
                         (b.getX() * a.getY() * c.getZ()));

      return (soma - diferenca);
    }

    public Ponto getIntersecao2(Raio raio) {
      Ponto retorno = null;
      Ponto Pa = Ponto.sub(raio.getOrigem(), this.getVertice3());
      Ponto Pb = Ponto.sub(this.getVertice1(), this.getVertice3());
      Ponto Pc = Ponto.sub(this.getVertice2(), this.getVertice3());
      Vetor inverteD = Vetor.mult( -1, raio.getDirecao());
      Ponto D = Ponto.soma(new Ponto(0, 0, 0), inverteD);
      float d = this.determinante(Pb, Pc, D);
      float dalfa = this.determinante(Pa, Pc, D);
      float dbeta = this.determinante(Pb, Pa, D);
      float dt = this.determinante(Pb, Pc, Pa);
      if (d == 0) {
        return retorno;
      }
      float alfa = dalfa / d;
      if (alfa < 0 || alfa > 1) {
        return retorno;
      }
      float beta = dbeta / d;
      if (beta < 0 || beta > 1) {
        return retorno;
      }
      float gama = 1 - (alfa + beta);
      if (gama < 0 || gama > 1) {
        return retorno;
      }
      float t = dt / d;
      if (t < 0) {
        return retorno;
      }
      retorno = Ponto.soma(raio.getOrigem(), Vetor.mult(t, raio.getDirecao()));
      retorno.setCor(this.getVertice1().getCor());
      retorno.setAlfa(alfa);
      retorno.setBeta(beta);
      retorno.setGama(gama);
      return retorno;
    }

  private float multPontoVetor(Ponto p, Vetor v) {
    return (v.getX() * p.getX()) + (v.getY() * p.getY()) + (v.getZ() * p.getZ());
  }

  public Ponto getIntersecao(Raio raio) {

    Vetor v1 = new Vetor(this.getVertice1(), this.getVertice2());
    Vetor v2 = new Vetor(this.getVertice1(), this.getVertice3());

    Vetor N = Vetor.produtoVetorial(raio.getDirecao(),v2);

    float det = Vetor.produtoInterno(v1,N);

    if (det == 0) {
      return null;
    }

    float invDet = 1 / det;

    Vetor tVec = new Vetor(this.getVertice1(),raio.getOrigem());

    float u =  Vetor.produtoInterno(tVec,N)*invDet;

    if (u < 0 || u > 1) {
      return null;
    }

    Vetor qVec = Vetor.produtoVetorial(tVec, v1);

    float v = Vetor.produtoInterno(raio.getDirecao(),qVec)*invDet;

    if (v < 0 || u + v > 1) {
      return null;
    }

    float t = Vetor.produtoInterno(v2,qVec)*invDet;

    Vetor vec = Vetor.produtoVetorial(tVec,v1);

    double dist = invDet * Vetor.produtoInterno(v2,vec);

    if (dist < 0) {
      return null;
    }

    float x = (1-(u+v))*this.getVertice1().getX() + u*this.getVertice2().getX() + v*this.getVertice3().getX();
    float y = (1-(u+v))*this.getVertice1().getY() + u*this.getVertice2().getY() + v*this.getVertice3().getY();
    float z = (1-(u+v))*this.getVertice1().getZ() + u*this.getVertice2().getZ() + v*this.getVertice3().getZ();

    Ponto p = new Ponto(x,y,z);
    p.setCor(this.getVertice1().getCor());
    p.setAlfa(u);
    p.setBeta(v);
    p.setGama((1-(u+v)));
    return p;
  }

  public String toString() {
    return "vertice1 = " + this.getVertice1() + "\nvertice2 = " +
        this.getVertice2() + "\nvertice3 = " + this.getVertice3();
  }

  public static void main(String[] args) {
    Ponto a, b, c;
    a = new Ponto(0, 0, 0);
    b = new Ponto(6, 0, 0);
    c = new Ponto(0, 6, 0);
    Triangulo t = new Triangulo(a, b, c);
    System.out.print("Vertices : ");
    System.out.println(a + " " + b + " " + c);
    System.out.println("Normal = " + t.getNormal());
    Raio r = new Raio(new Ponto(0, 0, 5),
                      new Vetor(new Ponto(0, 0, 5), new Ponto(0, 0, 0)));
    System.out.println(r);
    System.out.println(t.getIntersecao(r));
/*
    int pos = 0, neg = 0;
    for (int x = 0; x <= 6; x++) {
      for (int y = 0; y <= 6; y++) {
        r = new Raio(new Ponto(0, 0, 5),
                     new Vetor(new Ponto(0, 0, 5), new Ponto(x, y, 0)));
        System.out.println(r);
        System.out.println(t.getIntersecao(r));
        if (t.getIntersecao(r) != null) {
          pos++;
        }
        else {
          neg++;
        }
      }
    }
    System.out.println("pos = " + pos + " neg = " + neg);
*/
  }

}

